<?php
declare(strict_types=1);

namespace app\shop\logic;

use app\shop\enums\order\refund\RefundStatus;
use app\shop\enums\order\refund\RefundType;
use app\shop\enums\order\refund\RefundUserShipStatus;
use app\shop\exception\FailException;
use app\shop\exception\ParamsErrorException;
use app\shop\library\calculate\Calculate;
use app\shop\model\order\OrderDetailModel;
use app\shop\model\order\OrderModel;
use app\shop\model\order\OrderRefundModel;
use app\shop\service\LogService;
use app\shop\service\NotifyService;
use app\shop\service\OrderService;
use think\db\BaseQuery;
use think\Model;
use think\Paginator;
use Throwable;

class OrderRefundLogic extends BaseLogic
{
    /**
     * 售后列表
     * @param array $params
     * @return array|Paginator
     */
    public function list(array $params): Paginator|array
    {
        $query = OrderRefundModel::getQuery();

        $query = $this->buildEqualQuery($query, $params, [
            'user_id' => 'user_id',
            'status'  => 'status',
        ]);

        $query->field(['id', 'order_detail_id', 'status', 'audit_status', 'user_ship_status', 'create_time', 'apply_money', 'refund_num', 'refund_type'])
            ->with([
                'detail' => function ($query) {
                    $query->field(['id', 'order_id', 'goods_id', 'goods_name', 'price', 'pay_price', 'num', 'image', 'spec', 'evaluate_time']);
                }
            ])
            ->append(['status_text'])
            ->order(['id' => 'desc']);

        return OrderRefundModel::paginateListQuery($query);
    }

    /**
     * 售后详情
     * @param array $params
     * @return array|mixed|BaseQuery|Model
     * @throws FailException
     */
    public function detail(array $params): mixed
    {
        $query = OrderRefundModel::getQuery();

        $this->buildEqualQuery($query, $params, [
            'id'      => 'id',
            'user_id' => 'user_id',
        ]);

        $query->withoutField([
            'user_ship_time',
        ]);

        $query->with([
            'detail' => function ($query) {
                $query->field([
                    'id', 'order_id', 'goods_id', 'goods_name', 'price', 'pay_price', 'num', 'image', 'spec', 'evaluate_time'
                ]);
            },
        ]);

        $query->append(['status_text']);

        $result = $query->findOrEmpty();

        if ($result->isEmpty()) {
            throw new FailException('售后订单不存在');
        }

        return $result;
    }

    /**
     * 退款申请
     * @param array $params
     * @return true
     * @throws FailException
     * @throws ParamsErrorException
     */
    public function refund(array $params): bool
    {
        $order = OrderModel::where([
            'id' => $params['id'],
        ])->findOrEmpty();

        $detail = OrderDetailModel::where([
            'id' => $params['detail_id']
        ])->with(['refund'])->findOrEmpty();

        if ($order->isEmpty() || $detail->isEmpty()) {
            throw new FailException('订单异常,请刷新');
        }
        if ($detail->refund) {
            throw new FailException('该订单已申请售后,请勿重复提交');
        }
        $allowRefundTime = (new OrderService())->getApplyRefundTime();
        if (time() > $order->receive_time + $allowRefundTime) {
            throw new ParamsErrorException('很抱歉,当前订单已超过售后申请期限,请联系客服处理问题');
        }
        $maxRefundMoney = Calculate::newDecimal($detail->pay_price)->add($order->freight)->getValue();
        if ($params['apply_money'] > $maxRefundMoney) {
            throw new ParamsErrorException('很抱歉,申请金额超过限制');
        }

        $refundData = [
            'order_id'        => $order->id,
            'order_detail_id' => $detail->id,
            'user_id'         => $params['user_id'],
            'refund_type'     => $params['refund_type'],
            'refund_num'      => $params['refund_num'],
            'remark'          => $params['remark'] ?? '',
            'remark_images'   => $params['remark_images'] ?? '',
            'apply_money'     => $params['apply_money'] ?? 0,
        ];

        OrderModel::startTrans();
        $refundType = RefundType::getAllDescriptions()[$params['refund_type']];
        try {
            OrderRefundModel::create($refundData);
            LogService::orderStatusLog($order->id, $order->status, "用户申请售后($refundType)", $params['user_id']);

            (new NotifyService())->send('order_refund', $order->toArray());
        } catch (Throwable $e) {
            OrderModel::rollback();
            throw new FailException('售后申请失败', null, $e);
        }
        OrderModel::commit();

        return true;
    }

    /**
     * 退货信息录入
     * @param array $params
     * @return string
     * @throws FailException
     * @throws ParamsErrorException
     */
    public function refundReturn(array $params): string
    {
        $refund = OrderRefundModel::where([
            'id'      => $params['id'],
            'user_id' => $params['user_id']
        ])->findOrEmpty();
        if ($refund->isEmpty()) {
            throw new ParamsErrorException('售后单不存在');
        }
        if ($refund->status != RefundStatus::WAIT_AUDIT) {
            throw new FailException('售后状态异常');
        }

        try {
            $refund->user_ship_status   = RefundUserShipStatus::SHIPPED;
            $refund->user_ship_time     = time();
            $refund->user_ship_delivery = [
                'delivery_company_id' => $params['delivery_company_id'],
                'delivery_company'    => $params['delivery_company'],
                'delivery_no'         => $params['delivery_no'],
            ];

            $refund->save();
        } catch (Throwable $e) {
            throw new FailException('物流信息录入失败', null, $e);
        }

        return '物流信息录入成功';
    }
}